﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using BlackEagleLibrary;

namespace BlackEagleWCF
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    public class DatingService : IDatingService
    {

        /// <summary>
        /// Lägg till parameter:DirectMessage i databasen, i tabellen DirectMessage
        /// </summary>
        /// <param name="dm"></param>
        public void SendMessage(DirectMessageComposite dmc)
        {
            DirectMessage dm = ConvertToDirectMessage(dmc);

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                data.DirectMessage.AddObject(dm);
                data.SaveChanges();
            }
        }

        /// <summary>
        /// Tar emot ett PersonComposite-objekt, omvandlar det till ett Person-objekt och sparar objektet i tabellen Person.
        /// </summary>
        /// <param name="p"></param>
        public void AddProfile(PersonComposite p)
        {

            Person person = ConvertToPerson(p);

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                data.Person.AddObject(person);
                data.SaveChanges();
            }

        }

        /// <summary>
        /// Lägg till parameter:WallMessageComposite i tabellen WallMessage
        /// </summary>
        /// <param name="wm"></param>
        public void SendWallMessage(WallMessageComposite wm)
        {
            WallMessage w = ConvertToWallMessage(wm);

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                data.WallMessage.AddObject(w);
                data.SaveChanges();
            }
        }

        /// <summary>
        /// Lägg till parameter:FriendshipComposite i tabellen Friendship
        /// </summary>
        /// <param name="f"></param>
        public void FriendRequest(Guid friend1, Guid friend2)
        {

            Friendship friendship = new Friendship();
            friendship.Friend1 = friend1;
            friendship.Friend2 = friend2;
            friendship.Confirmed = false;

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                data.Friendship.AddObject(friendship);
                data.SaveChanges();

            }
        }

        /// <summary>
        /// Uppdatera kolumnen confirmed till true i tabellen Friendship där friend1 i databasen matchar friend1 i inkommande objektet, samma för friend2.
        /// Om ID för både friend1 och friend2 matchas så har deras Friendship hittats.
        /// </summary>
        /// <param name="f"></param>
        public void AcceptFriendRequest(Guid friend1, Guid friend2)
        {
            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                Friendship f = data.Friendship
                    .Where(x => x.Friend1.Equals(friend1) && x.Friend2.Equals(friend2)).First();
                f.Confirmed = true;
                data.SaveChanges();

            }
        }

        /// <summary>
        /// Hittar rätt friendship genom att matcha friend1 och friend2 med ett friendship i databasen
        /// När ett vänansökan avslås tas deras friendship bort i databasen.
        /// </summary>
        /// <param name="friend1"></param>
        /// <param name="friend2"></param>
        public void DenyFriendRequest(Guid friend1, Guid friend2)
        {
            using(BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                Friendship f = data.Friendship
                    .Where(x => x.Friend1.Equals(friend1) && x.Friend2.Equals(friend2))
                    .Where(x => x.Confirmed == false)
                    .First();
                data.DeleteObject(f);
                data.SaveChanges();
            }
        }

        /// <summary>
        /// Försöker att hitta en vänskap mellan två personer genom att matcha friend1 och friend2.
        /// </summary>
        /// <param name="friend1"></param>
        /// <param name="friend2"></param>
        /// <returns>Om en vänskap hittas så returneras true, om det inte hittas så returneras false</returns>
        public bool CheckForFriendship(Guid friend1, Guid friend2)
        {
            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                if(data.Friendship.Any(x => x.Friend1.Equals(friend1) && x.Friend2.Equals(friend2)) || data.Friendship.Any(x => x.Friend1.Equals(friend2) && x.Friend2.Equals(friend1))) 
                {
                    return true;
                } else 
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Söker efter Person vars förnamn, efternamn eller kön(sex) matchar parameter.
        /// </summary>
        /// <param name="s"></param>
        /// <returns>Returnerar en List<PersonComposite> av resultatet</returns>
        public List<PersonComposite> SearchPersons(string name, int sex)
        {
            List<Person> result = new List<Person>();
            List<PersonComposite> persons = new List<PersonComposite>();

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                result = (from p in data.Person
                          where p.Fnamn.Contains(name) || p.Enamn.Contains(name)
                          where p.Sex.Value == sex
                          select p).ToList();
            }

            foreach (var item in result)
            {
                PersonComposite p = new PersonComposite();
                p.ID = item.ID;
                p.Fnamn = item.Fnamn;
                p.Enamn = item.Enamn;
                p.PictureUrl = item.PictureUrl;
                p.BirthDate = (DateTime)(item.BirthDate);
                p.Sex = (int)item.Sex;
                p.Email = item.Email;

                persons.Add(p);
            }

            return persons;
        }

        /// <summary>
        /// Hämta alla relationer från friendship där ena personen har parameter:id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public List<PersonComposite> GetFriends(Guid id)
        {
            List<Friendship> result = new List<Friendship>();
            List<FriendshipComposite> friendships = new List<FriendshipComposite>();
            List<Guid> friendIDs = new List<Guid>();
            List<PersonComposite> friends = new List<PersonComposite>();

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                
                result = (from friendship in data.Friendship
                          where friendship.Friend1 == id || friendship.Friend2 == id
                          where friendship.Confirmed == true
                          select friendship).ToList();
            }

            foreach (var item in result)
            {
                FriendshipComposite f = ConvertToFriendshipComposite(item);
                friendships.Add(f);

            }
            foreach (var item in friendships)
            {

                if (item.Friend1 == id)
                {
                    friendIDs.Add(item.Friend2);
                }
                else
                {
                    friendIDs.Add(item.Friend1);
                }
            }
            foreach (var item in friendIDs)
            {
                friends.Add(GetProfile(item));
                
            }

            return friends;
        }

        /// <summary>
        /// Hämtar alla friendship, som inte är accepterade, för parameter:id där id matchar friend2 (den tillfrågade)
        /// Alltså, alla vänansökningar/friendrequest för personen med matchande id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public List<PersonComposite> GetFriendRequests(Guid id)
        {
            List<Friendship> friends = new List<Friendship>();
            List<PersonComposite> result = new List<PersonComposite>();

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {

                friends = (from friendship in data.Friendship
                          where friendship.Friend2 == id
                          where friendship.Confirmed == false
                          select friendship).ToList();
            }

            foreach(var friendship in friends) 
            {
                PersonComposite p = GetProfile(friendship.Friend1);
                result.Add(p);
            }

            return result;
        }

        /// <summary>
        /// Hämta ett person-objekt med id parameter:id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public PersonComposite GetProfile(Guid id)
        {
            List<Person> result = new List<Person>();

            PersonComposite p = new PersonComposite();

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                result = (from person in data.Person
                          where person.ID == id
                          select person).ToList();
            }

            foreach (var item in result)
            {
                p.ID = item.ID;
                p.Fnamn = item.Fnamn;
                p.Enamn = item.Enamn;
                p.PictureUrl = item.PictureUrl;
                p.BirthDate = (DateTime)(item.BirthDate);
                p.Sex = (int)item.Sex;
                p.Email = item.Email;
                p.PersonalDesc = item.PersonalDesc;

            }

            return p;

        }


        /// <summary>
        /// Metoden ska uppdatera en profil med nya värden
        /// Problemet är hur tomma fält i det inkommande objektet ska hanteras
        /// Om det inte hanteras kommer värdet i databasen att skrivas över med ett tomt värde.
        /// Alt. 1 Värdena kontrolleras individuellt med varsin if-sats (If värdet != null så spara värdet)
        /// </summary>
        /// <param name="p"></param>
        public void UpdateProfile(PersonComposite p)
        {
            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {

                Person pers = data.Person
                    .FirstOrDefault(x => x.ID == p.ID);
                pers.Fnamn = p.Fnamn;
                pers.Enamn = p.Enamn;
                pers.Email = p.Email;
                pers.BirthDate = p.BirthDate;
                pers.PictureUrl = p.PictureUrl;
                pers.PersonalDesc = p.PersonalDesc;
                data.SaveChanges();

            }
        }

        /// <summary>
        ///  Hämtar och returnerar en List<PersonComposite> med 5 st slumpmässigt valda Person
        /// </summary>
        /// <returns></returns>
        public List<PersonComposite> GetSpotlight()
        {
            List<Person> personList = new List<Person>();
            List<PersonComposite> resultList = new List<PersonComposite>();

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                personList = (from p in data.Person
                              orderby Guid.NewGuid()
                              select p).Take(5).ToList();
            }

            foreach (var person in personList)
            {
                PersonComposite p = ConvertToPersonComposite(person);
                resultList.Add(p);
            }

            return resultList;
        }

        

        /// <summary>
        /// Returnerar alla kommentarer/wallmessages på en användares (parameter:id) profil
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public List<WallMessageComposite> GetWallMessages(Guid id)
        {
            List<WallMessage> result = new List<WallMessage>();
            List<WallMessageComposite> messages = new List<WallMessageComposite>();

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                result = (from msg in data.WallMessage
                              where msg.Receiver == id
                              select msg).OrderByDescending(c => c.SendDate).ToList();
            }

            foreach (var msg in result)
            {
                messages.Add(ConvertToWallMessageComposite(msg));
            }

            return messages;
        }

        /// <summary>
        /// Returnera för- och efternamn för användarid från parameter:users
        /// </summary>
        /// <param name="users"></param>
        /// <returns></returns>
        public List<String> GetAuthors(List<Guid> users)
        {
            List<String> authors = new List<String>();
            int counter = 0;
            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {

                foreach (var user in users)
                {
                    Guid id = users[counter];

                    var query = from p in data.Person
                                where p.ID == id
                                select new
                                {
                                    p.Fnamn,
                                    p.Enamn
                                };
                    authors.Add(query.First().Fnamn + " " + query.First().Enamn);
                    counter++;
                }
            }

            return authors;
        }

        /// <summary>
        /// Returnera antal nya meddelanden för en användare med parameter:id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>

        public int CountNewMessages(Guid id)
        {
            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                var query = (from p in data.DirectMessage
                             where p.Receiver == id 
                             where p.IsRead == false
                             select p).Count();

                int count = query;
                return count;
            }



        }

        /// <summary>
        /// Räknar antal nya vänansökningar/friendrequests
        /// Matchar ingående persons ID med friend2 (den tillfrågade) i friendship-tabellen samt skall Confirmed vara false (alltså inte accepterad)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public int CountNewFriends(Guid id)
        {
            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                var query = (from p in data.Friendship
                             where p.Friend2 == id
                             where p.Confirmed == false
                             select p).Count();

                int count = query;
                return count;
            }



        }

        /// <summary>
        /// Får en lista av person, går igenom listan och matchar varje person i listan med person i databasen och hämtar länk till profilbild för varje person.
        /// </summary>
        /// <param name="users"></param>
        /// <returns></returns>
        public List<String> GetProfilePictures(List<Guid> users)
        {
            List<String> pictureUrls = new List<String>();

            int counter = 0;
            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {

                foreach (var user in users)
                {
                    Guid id = users[counter];

                    var query = (from p in data.Person
                                 where p.ID == id
                                 select p.PictureUrl).First();
                    pictureUrls.Add(query);
                    counter++;
                }
            }

            return pictureUrls;
        }

        /// <summary>
        /// Hämtar alla DirectMessage (privatmeddelanden) för en person med parameter:id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public List<DirectMessageComposite> GetMessages(Guid id)
        {
            List<DirectMessageComposite> result = new List<DirectMessageComposite>();
            List<DirectMessage> messages = new List<DirectMessage>();

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
                messages = (from dm in data.DirectMessage
                            where dm.Receiver == id
                            select dm).OrderByDescending(x => x.SendDate).ToList();
            }

            foreach (var dm in messages)
            {
                DirectMessageComposite dmc = ConvertToDirectMessageComposite(dm);
                result.Add(dmc);
            }

            return result;
        }

        /// <summary>
        /// Konverterar från WallMessageComposite till WallMessage
        /// </summary>
        /// <param name="wc"></param>
        /// <returns></returns>
        public WallMessage ConvertToWallMessage(WallMessageComposite wc)
        {
            WallMessage w = new WallMessage();
            w.ID = wc.ID;
            w.Content = wc.Content;
            w.Sender = wc.Sender;
            w.Receiver = wc.Receiver;
            w.SendDate = wc.SendDate;

            return w;
        }

        /// <summary>
        /// Konverterar från WallMessage till WallMessageComposite
        /// </summary>
        /// <param name="w"></param>
        /// <returns></returns>
        public WallMessageComposite ConvertToWallMessageComposite(WallMessage w)
        {
            WallMessageComposite wc = new WallMessageComposite();
            wc.ID = w.ID;
            wc.Content = w.Content;
            wc.Sender = w.Sender;
            wc.Receiver = w.Receiver;
            wc.SendDate = (DateTime)w.SendDate;

            return wc;
        }

        /// <summary>
        /// Konverterar från DirectMessageComposite till DirectMessage
        /// </summary>
        /// <param name="dmc"></param>
        /// <returns></returns>
        public DirectMessage ConvertToDirectMessage(DirectMessageComposite dmc)
        {
            DirectMessage dm = new DirectMessage();
            dm.ID = dmc.ID;
            dm.Title = dmc.Title;
            dm.Content = dmc.Content;
            dm.Receiver = dmc.Receiver;
            dm.Sender = dmc.Sender;
            dm.SendDate = dmc.SendDate;
            dm.IsRead = dmc.IsRead;

            return dm;
        }

        /// <summary>
        /// Konverterar från DirectMessage till  DirectMessageComposite
        /// </summary>
        /// <param name="dm"></param>
        /// <returns></returns>
        public DirectMessageComposite ConvertToDirectMessageComposite(DirectMessage dm)
        {
            DirectMessageComposite dmc = new DirectMessageComposite();
            dmc.ID = (int)dm.ID;
            dmc.Title = dm.Title;
            dmc.Content = dm.Content;
            dmc.Receiver = dm.Receiver;
            dmc.Sender = dm.Sender;
            dmc.SendDate = (DateTime)dm.SendDate;
            dmc.IsRead = (bool)dm.IsRead;

            return dmc;
        }

        /// <summary>
        /// Konverterar från PersonComposite till Person
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private Person ConvertToPerson(PersonComposite p)
        {
            Person person = new Person();

            person.ID = p.ID;
            person.Fnamn = p.Fnamn;
            person.Enamn = p.Enamn;
            person.PictureUrl = p.PictureUrl;
            person.BirthDate = (DateTime)(p.BirthDate);
            person.Sex = (int)p.Sex;
            person.Email = p.Email;
            person.PersonalDesc = p.PersonalDesc;

            return person;
        }

        /// <summary>
        /// Konverterar från Person till PersonComposite
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private PersonComposite ConvertToPersonComposite(Person p)
        {
            PersonComposite person = new PersonComposite();

            person.ID = p.ID;
            person.Fnamn = p.Fnamn;
            person.Enamn = p.Enamn;
            person.PictureUrl = p.PictureUrl;
            person.BirthDate = (DateTime)(p.BirthDate);
            person.Sex = (int)p.Sex;
            person.Email = p.Email;
            person.PersonalDesc = p.PersonalDesc;

            return person;
        }

        /// <summary>
        /// Konverterar från FriendshipComposite till Friendship
        /// </summary>
        /// <param name="fc"></param>
        /// <returns></returns>
        private Friendship ConvertToFriendship(FriendshipComposite fc)
        {
            Friendship f = new Friendship();
            f.ID = fc.ID;
            f.Friend1 = fc.Friend1;
            f.Friend2 = fc.Friend2;
            f.Confirmed = fc.Confirmed;
            return f;
        }

        /// <summary>
        /// Konverterar från Friendship till FriendshipComposite
        /// </summary>
        /// <param name="f"></param>
        /// <returns></returns>
        private FriendshipComposite ConvertToFriendshipComposite(Friendship f)
        {
            FriendshipComposite fc = new FriendshipComposite();
            fc.ID = f.ID;
            fc.Friend1 = f.Friend1;
            fc.Friend2 = f.Friend2;
            fc.Confirmed = (bool)f.Confirmed;
            return fc;
        }


        /// <summary>
        /// Hämta ett DirectMessage som matchar paramter:id. Ändra IsRead till true.
        /// </summary>
        /// <param name="id"></param>
        public void MarkMessageAsRead(int id)
        {

            using (BlackEagleDatingDBEntities data = new BlackEagleDatingDBEntities())
            {
               DirectMessage dm = (from d in data.DirectMessage
                     where d.ID == id
                     select d).First();

                dm.IsRead = true;
                data.SaveChanges();
            }   
        }
    }
}
